package com.example.demo.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.aliyun.oss.OSS;
import com.example.demo.configuration.AliyunOssConfig;
import com.example.demo.constant.RedisConstant;
import com.example.demo.constant.TaskConstant;
import com.example.demo.controller.bean.Result;
import com.example.demo.dto.*;
import com.example.demo.mapper.entity.*;
import com.example.demo.service.StudentBadgeService;
import com.example.demo.service.StudentCouponsService;
import com.example.demo.service.StudentPointsService;
import com.example.demo.service.StudentTaskService;
import com.example.demo.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author Lucy
 * @create 2024-02-27 11:45
 */
@RequestMapping("taskBag")
@Api(value = "任务背包", tags = {"任务背包接口"})
@RestController
@Slf4j
public class TaskBagController {

    @Autowired
    private StudentPointsService pointsService;

    @Autowired
    private StudentBadgeService badgeService;

    @Autowired
    private StudentCouponsService couponsService;

    @Autowired
    private StudentTaskService taskService;

    @Autowired
    private RedisUtil redisUtil;

    private OSS ossClient;

    @ResponseBody
    @ApiOperation("获取任务背包头部的显示信息")
    @RequestMapping(value = "getTaskBagHead", method = {RequestMethod.POST,  RequestMethod.GET} )
    public Result<Object> getTaskBagHead(){
        int studentId = StpUtil.getLoginIdAsInt();
        Map<String, Object> map = new HashMap<>();
        String periodName = null;
        if (LocalDateTime.now().isBefore(TaskConstant.PERIOD1_END_DATE)) {
            // 当前时间在第一阶段结束之前
            periodName = TaskConstant.PERIOD1_NAME;
        }else if(LocalDateTime.now().isBefore(TaskConstant.PERIOD2_END_DATE)){
            // 当前时间在第二阶段结束之前
            periodName = TaskConstant.PERIOD2_NAME;
        }else{
            // 当前时间在第三阶段结束之前
            periodName = TaskConstant.PERIOD3_NAME;
        }
        map.put("periodName", periodName);
        int points = pointsService.selectStudentPointsByStudentId(studentId).getPoints();
        map.put("points", points);
        int badgeNumber = badgeService.selectBadgeNumber(studentId);
        map.put("badgeNumber", badgeNumber);
        return Result.ok(map);
    }

    @ApiOperation("获取主线任务列表")
    @RequestMapping(value = "getMainTasksList", method = {RequestMethod.POST})
    public Result<List<TaskListDTO>> getMainTasksList(){
        int studentId = StpUtil.getLoginIdAsInt();
        List<Task> mainTasksList =  taskService.getMORSTasksList(1);
        List<StudentTask> studentTaskList = taskService.selectStudentTasksListByStudentId(studentId);
        List<TaskListDTO> mainTasksListDTO =  new ArrayList<>();
        Pattern pattern = Pattern.compile("\\d+");
        for(Task task : mainTasksList){
            for(StudentTask studentTask : studentTaskList){
                if(task.getTaskId() == studentTask.getTaskId()){
                    TaskListDTO dto = new TaskListDTO();
                    dto.setTaskId(task.getTaskId());
                    dto.setTaskType(task.getTaskType());
                    dto.setTaskName(task.getTaskName());
                    dto.setTaskLabel(task.getTaskLabel());
                    dto.setTaskStatus(studentTask.getCompletionStatus());
                    dto.setPointsAwarded(task.getPointsAwarded());
                    if(task.getBadgeAwarded() != 0){
                        dto.setBadgeName(badgeService.selectBadgeById(task.getBadgeAwarded()).getName());
                    }
                    if(task.getCouponsAwarded() != 0){
                        dto.setCouponsName(couponsService.selectCouponsById(task.getCouponsAwarded()).getCouponsName());
                    }
                    Matcher matcher = pattern.matcher(task.getAttributesAwarded());
                    int i = 0;
                    int[] attributesAwarded = new int[8];
                    while (matcher.find()) {
                        attributesAwarded[i] = Integer.parseInt(matcher.group());
                        i++;
                    }
                    dto.setAttributesAwarded(attributesAwarded);
                    mainTasksListDTO.add(dto);
                }
            }
        }
        List<TaskListDTO> sortedTasksList = mainTasksListDTO.stream()
                .sorted(Comparator.comparing(TaskListDTO::getTaskStatus).reversed())
                .collect(Collectors.toList());
        return Result.ok(sortedTasksList);
    }

    @ApiOperation("获取支线任务列表")
    @RequestMapping(value = "getSideTasksList", method = {RequestMethod.POST})
    public Result<List<TaskListDTO>> getSideTasksList(){
        int studentId = StpUtil.getLoginIdAsInt();
        List<Task> sideTasksList =  taskService.getMORSTasksList(2);
        List<StudentTask> studentTaskList = taskService.selectStudentTasksListByStudentId(studentId);
        List<TaskListDTO> sideTasksListDTO =  new ArrayList<>();
        Pattern pattern = Pattern.compile("\\d+");
        for(Task task : sideTasksList){
            for(StudentTask studentTask : studentTaskList){
                if(task.getTaskId() == studentTask.getTaskId()){
                    TaskListDTO dto = new TaskListDTO();
                    dto.setTaskId(task.getTaskId());
                    dto.setTaskType(task.getTaskType());
                    dto.setTaskName(task.getTaskName());
                    dto.setTaskLabel(task.getTaskLabel());
                    dto.setTaskStatus(studentTask.getCompletionStatus());
                    dto.setPointsAwarded(task.getPointsAwarded());
                    if(task.getBadgeAwarded() != 0){
                        dto.setBadgeName(badgeService.selectBadgeById(task.getBadgeAwarded()).getName());
                    }
                    if(task.getCouponsAwarded() != 0){
                        dto.setCouponsName(couponsService.selectCouponsById(task.getCouponsAwarded()).getCouponsName());
                    }
                    Matcher matcher = pattern.matcher(task.getAttributesAwarded());
                    int i = 0;
                    int[] attributesAwarded = new int[8];
                    while (matcher.find()) {
                        attributesAwarded[i] = Integer.parseInt(matcher.group());
                        i++;
                    }
                    dto.setAttributesAwarded(attributesAwarded);
                    sideTasksListDTO.add(dto);
                }
            }
        }
        List<TaskListDTO> sortedTasksList = sideTasksListDTO.stream()
                .sorted(Comparator.comparing(TaskListDTO::getTaskStatus).reversed())
                .collect(Collectors.toList());
        return Result.ok(sortedTasksList);
    }

    @ApiOperation("获取冒险指南信息")
    @GetMapping("/getAdventureGuideInfo/{taskId}")
    public Result<AdventureGuideDTO> getAdventureGuideInfo(@PathVariable int taskId) {
        Task task = taskService.selectTaskById(taskId);
        Pattern pattern = Pattern.compile("\\d+");
        AdventureGuideDTO dto = new AdventureGuideDTO();
        dto.setTaskId(task.getTaskId());
        dto.setEndTime(task.getEndTime());
        dto.setTaskSequence(task.getTaskSequence());
        dto.setPointsAwarded(task.getPointsAwarded());
        Matcher matcher = pattern.matcher(task.getAttributesAwarded());
        int i = 0;
        int[] attributesAwarded = new int[8];
        while (matcher.find()) {
            attributesAwarded[i] = Integer.parseInt(matcher.group());
            i++;
        }
        dto.setAttributesAwarded(attributesAwarded);
        dto.setBadgeName(badgeService.selectBadgeById(task.getBadgeAwarded()).getName());
        if(task.getCouponsAwarded() != 0){
            dto.setCouponsName(couponsService.selectCouponsById(task.getCouponsAwarded()).getCouponsName());
        }
        return Result.ok(dto);
    }

    @ApiOperation("拍照打卡类任务-获取任务清单")
    @GetMapping("/getCheckinDescription/{taskId}")
    public Result<Object> getCheckinDescription(@PathVariable int taskId) {
        Task task = taskService.selectTaskById(taskId);
        Map<String, Object> map = new HashMap<>();
        // 定义日期时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将String类型的startTime转换为LocalDateTime
        LocalDateTime startTime = LocalDateTime.parse(task.getStartTime(), formatter);
        // 计算两个日期之间的差异
        Duration duration = Duration.between(startTime, TaskConstant.PERIOD1_END_DATE);
        // 获取相差的天数
        long daysDifference = duration.toDays();
        if(daysDifference < 0){
            map.put("taskLocation",task.getTaskLocation());
            map.put("latitude",task.getLatitude());
            map.put("longitude",task.getLongitude());
        }else{
            map.put("daysDifference",daysDifference);
        }
        int studentId = StpUtil.getLoginIdAsInt();
        StudentTask studentTask = taskService.selectStudentTask(studentId, taskId);
        List<ItemDTO> checkinList = new ArrayList<>();
        String checkinDescription = taskService.selectTaskById(taskId).getCheckinDescription();
        String[] strItemIds = checkinDescription.split(","); // 使用逗号分割字符串
        int[] itemIds = new int[strItemIds.length]; // 创建一个整型数组来存储数字
        // 将分割出来的字符串转换为整数并存储到整型数组中
        for (int i = 0; i < strItemIds.length; i++) {
            itemIds[i] = Integer.parseInt(strItemIds[i]);
        }
        for(int itemId : itemIds){
            Item item = taskService.selectItemById(itemId);
            ItemDTO dto = new ItemDTO();
            dto.setItem(item);
            CheckinImage checkinImage = taskService.selectCheckinImage(studentId, taskId, itemId);
            if(checkinImage == null){
                dto.setItemStatus(0);
            }else if(studentTask.getCompletionStatus() == 3){
                dto.setItemStatus(3);
            }else if(checkinImage.getCheckinStatus() == 2){
                dto.setItemStatus(2);
            }else{
                dto.setItemStatus(1);
            }
            checkinList.add(dto);
        }
        map.put("checkinList",checkinList);
        return Result.ok(map);
    }

    @ApiOperation(value = "拍照打卡类任务-上传学生拍照打卡照片")
    @PostMapping("/uploadCheckinImage")
    public Result<Object> uploadCheckinImage(@RequestPart("taskId") int taskId,@RequestPart("itemId") int itemId, @RequestPart (value = "file", required = true)MultipartFile file) throws IOException {
        Map<String, Object> map = new HashMap<>();
        // 获取当前会话账号id
        int studentId = StpUtil.getLoginIdAsInt();
//        int taskId = dto.getTaskId();
//        int itemId = dto.getItemId();

        CheckinImage image = taskService.selectCheckinImage(studentId, taskId, itemId);
        if(image == null){
            image = new CheckinImage(); // 创建一个新的CheckinImage实例
            image.setStudentId(studentId);
            image.setTaskId(taskId);
            image.setItemId(itemId);
            taskService.insertCheckinImage(image);
        }

        Item item = taskService.selectItemById(itemId);

        //用文件地址调用通用物体和场景识别API
        File scratchFile = File.createTempFile("temp", null);
        try (FileOutputStream fos = new FileOutputStream(scratchFile)) {
            fos.write(file.getBytes());
        }
        int recognitionResult = ObjectRecognitionUtil.advancedGeneral(item.getItemName(), scratchFile);
        int errorNum = 0;
        String key = "CheckinImage" + ":" + taskId + ":" + studentId + ":" + itemId;
        if (redisUtil.hasKey(key)) {
            errorNum = (int) redisUtil.get(key);
        }

        if(recognitionResult == 2 && errorNum < 3){
            image.setRecognitionStatus(1);
            image.setCheckinStatus(2);
            taskService.updateCheckinStatus(image);
            redisUtil.set(key, errorNum + 1);
            map.put("itemStatus",2);
            map.put("layTitle","打卡失败");
            map.put("layContent","打卡照片识别失败，请重新上传");
            return Result.ok(map);
        }
        //从上传的文件中获取原始文件名
        String originalFileName = file.getOriginalFilename();
        int i = originalFileName.lastIndexOf(".");
        String png = originalFileName.substring(i);//获取文件扩展名
        //存储空间的名字
        String bucketName = "seedling-classmate";
        //创建存储对象
        ossClient = AliyunOssConfig.ossClient();

        //设置文件名并上传到OSS
        String fileName = "checkinImage/id-" +image.getImageId()+"-"+ UUID.randomUUID().toString().substring(0,12)+png;
        taskService.insertCheckinImageFileName(image.getImageId(), fileName);
        ossClient.putObject(bucketName, fileName, file.getInputStream());   //之后在数据库中保存fileNam
        ossClient.shutdown();

        if(recognitionResult == 2 && errorNum == 3){
            image.setRecognitionStatus(2);
            image.setCheckinStatus(2);
            image.setImageUrl(fileName);
            taskService.updateCheckinStatus(image);
            taskService.updateCompletionStatus(studentId, taskId, 3);
            map.put("itemStatus",3);
            map.put("layTitle","温馨提示");
            map.put("layContent","打卡失败次数过多，转入人工审核");
            return Result.ok(map);
        }
        redisUtil.del(key);
        image.setRecognitionStatus(1);
        image.setCheckinStatus(1);
        image.setImageUrl(fileName);
        taskService.updateCheckinStatus(image);
        map.put("itemStatus",1);
        map.put("layTitle","打卡成功");
        return Result.ok(map);
    }

    @ApiOperation(value = "拍照打卡类任务-获取任务状态的弹出层")
    @PostMapping("/getLayer")
    public Result<Object> getLayer(@RequestBody GetLayerDTO dto){
        int studentId = StpUtil.getLoginIdAsInt();
        int taskId = dto.getTaskId();
        int itemId = dto.getItemId();
        Map<String, Object> map = new HashMap<>();
        StudentTask studentTask = taskService.selectStudentTask(studentId, taskId);
        CheckinImage checkinImage = taskService.selectCheckinImage(studentId, taskId, itemId);
        if(studentTask.getCompletionStatus() == 3){
            map.put("itemStatus",3);
            map.put("layTitle","温馨提示");
            map.put("layContent","打卡失败次数过多，转入人工审核");
        }else if(checkinImage.getCheckinStatus() == 1 || studentTask.getReviewStatus() == 1){
            map.put("itemStatus",1);
            map.put("layTitle","打卡成功");
        }else if(checkinImage.getCheckinStatus() == 2){
            map.put("itemStatus",2);
            map.put("layTitle","打卡失败");
            map.put("layContent","打卡照片识别失败，请重新上传");
        }else{
            map.put("itemStatus",2);
            map.put("layTitle","打卡失败");
            map.put("layContent",studentTask.getReviewerComments());
        }
        return Result.ok(map);
    }

    @ApiOperation("拍照打卡类任务-修改任务完成状态")
    @GetMapping("/updateTaskStatus/{taskId}")
    public Result<Object> updateTaskStatus(@PathVariable int taskId) {
        int studentId = StpUtil.getLoginIdAsInt();
        Task task = taskService.selectTaskById(taskId);
        taskService.updateCompletionStatus(studentId, taskId, 2);
        //获取完成任务的积分奖励
        pointsService.updateStudentPoints(studentId, task.getPointsAwarded(), 0);
        //获取完成任务的属性奖励和徽章奖励，同时根据更新后的属性和徽章更新徽章
        taskService.receiveTaskReward(studentId, taskId);
        //获取完成任务的优惠券奖励
        if(task.getCouponsAwarded() != 0) couponsService.insertStudentCoupons(studentId, task.getCouponsAwarded());
        //StudentPoints studentPoints = pointsService.selectStudentPointsByStudentId(studentId);
        //redisUtil.addOrUpdate(RedisConstant.Student_Points_Rank_Name,studentId,studentPoints.getPoints());
        return Result.ok("任务完成");
    }

    @ApiOperation(value = "扫码识别类任务and视觉识别类任务-获取任务详情页信息")
    @GetMapping("/getTaskDetialInfo/{taskId}")
    public Result<Object> getTaskDetialInfo(@PathVariable int taskId) {
        Task task = taskService.selectTaskById(taskId);
        Map<String, Object> map = new HashMap<>();
        map.put("taskName",task.getTaskName());
        map.put("taskLocation",task.getTaskLocation());
        map.put("taskLabel",task.getTaskLabel());
        map.put("latitude",task.getLatitude());
        map.put("longitude",task.getLongitude());
        return Result.ok(map);
    }

    @ApiOperation(value = "扫码识别类任务-获取生成二维码参数")
    @GetMapping("/getQrCodeContent/{taskId}")
    public Result<String> getQrCodeContent(@PathVariable int taskId) {
        int studentId = StpUtil.getLoginIdAsInt();
        String formattedStudentId = String.format("%06d", studentId);
        String formattedTaskId = String.format("%06d", taskId);
        String qrCodeContent = "stkaaa" + CodeUtil.generateMixCode(6) + formattedStudentId + formattedTaskId;
        String key = "QRCODE" + ":" + formattedStudentId + ":" + formattedTaskId;
        long time = TaskConstant.QRCodeExpiration_Time;
        redisUtil.set(key, qrCodeContent, time);
        return Result.ok(qrCodeContent);
    }

    @ApiOperation("线上答题任务-获取试题")
    @GetMapping("/getQuestion/{taskId}")
    public Result<Object> getQuestion(@PathVariable int taskId) {
        Map<String, Object> map = new HashMap<>();
        Task task = taskService.selectTaskById(taskId);
        map.put("examDuration", task.getExamDuration());
        map.put("totalQuestion",task.getTotalQuestions());
        List<Question> questionList = taskService.selectQuestionListByBankId(task.getBankId());
        Random random = new Random();
        Collections.shuffle(questionList, random);
        List<Question> selectedQuestions = questionList.subList(0, task.getTotalQuestions());
        List<QuestionDTO> questionDTOList = new ArrayList<>();
        for(Question question : selectedQuestions){
            QuestionDTO dto = new QuestionDTO();
            dto.setQuestionId(question.getQuestionId());
            dto.setScore(question.getScore());
            dto.setQuestionType(question.getQuestionType());
            if(question.getQuestionType() == 3){
                dto.setQuestionText(question.getQuestionText());
                dto.setOptionA(question.getOptionA());
                dto.setOptionB(question.getOptionB());
            }else{
                dto.setQuestionText(question.getQuestionText());
                dto.setOptionA(question.getOptionA());
                dto.setOptionB(question.getOptionB());
                dto.setOptionC(question.getOptionC());
                dto.setOptionD(question.getOptionD());
            }
            questionDTOList.add(dto);
        }
        map.put("questionList", questionDTOList);
        return Result.ok(map);
    }

    @ApiOperation("线上答题类任务-获取测试结果")
    @RequestMapping(value = "getExamResult", method = {RequestMethod.POST})
    public Result<Object> getExamResult(@RequestBody AnswerListDTO answerListDTO) {
        int taskId = answerListDTO.getTaskId();
        List<AnswerDTO> answerList = answerListDTO.getAnswerDTO();
        Task task = taskService.selectTaskById(taskId);
        int studentId = StpUtil.getLoginIdAsInt();
        int totalScore = 0;
        List<Question> questionList = taskService.selectQuestionListByBankId(task.getBankId());
        for(AnswerDTO answerDTO : answerList){
            for(Question question : questionList){
                if(question.getQuestionId() == answerDTO.getQuestionId()){
                    StudentAnswerRecord record = new StudentAnswerRecord();
                    record.setTaskId(taskId);
                    record.setStudentId(studentId);
                    record.setQuestionId(answerDTO.getQuestionId());
                    record.setChosenAnswer(answerDTO.getAnswer());
                    if(question.getCorrectAnswer() == answerDTO.getAnswer()){
                        record.setIsCorrect(1);
                        totalScore += question.getScore();
                    }else{
                        record.setIsCorrect(2);
                    }
                    taskService.insertStudentAnswerRecord(record);
                }
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("totalScore", totalScore);
        if(totalScore < task.getPassingScore()){
            map.put("isPass", 0);
            map.put("massage", ExamResultUtil.getRandomFailMessage());
            taskService.updateCompletionStatus(studentId, taskId, 5);
        }else{
            map.put("isPass", 1);
            map.put("massage", ExamResultUtil.getRandomPassMessage());
            taskService.updateCompletionStatus(studentId, taskId, 2);
            //获取完成任务的积分奖励
            pointsService.updateStudentPoints(studentId, task.getPointsAwarded(), 0);
            //获取完成任务的属性奖励和徽章奖励，同时根据更新后的属性和徽章更新徽章
            taskService.receiveTaskReward(studentId, taskId);
            //获取完成任务的优惠券奖励
            if(task.getCouponsAwarded() != 0) couponsService.insertStudentCoupons(studentId, task.getCouponsAwarded());
        }
        return Result.ok(map);
    }
}
